using System;
using System.Text;

using Google.GData.AccessControl;
using Google.GData.Calendar;
using Google.GData.Contacts;
using Google.GData.Client;
using Google.GData.Extensions;
using System.Collections;
using System.Diagnostics;
using GSync;

namespace GSync.GoogleSystem
{
    class GCalendar
    {
        private  String userName, userPassword, feedUri;

        private CalendarService service;
        Hashtable calendari, events;
        public  String UserPassword
        {
            get { return userPassword; }
            set { userPassword = value; }
        }

        public  String FeedUri
        {
            get { return feedUri; }
            set { feedUri = value; }
        }

        public  String UserName
        {
            get { return userName; }
            set { userName = value; }
        }

        public void addCalendario(GSItem cal)
        {
            if (calendari == null)
            {
                calendari = new Hashtable(1);
                calendari.Add(cal.Title.ToString(),
                                             cal);
            }
        }

        /// <summary>
        /// Prints a list of the user's calendars.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        public ICollection RetriveUserCalendars()
        {
            FeedQuery query = new FeedQuery("http://www.google.com/calendar/feeds/default");
            calendari = new Hashtable(1);
            // Tell the service to query:
            try
            {
                AtomFeed calFeed = service.Query(query);
                if (calFeed != null)
                {
                    calendari = new Hashtable(calFeed.Entries.Count);
                  //  calendari.Add("Tutti","http://www.google.com/calendar/feeds/"+userName+"/private/full");
                    for (int i = 0; i < calFeed.Entries.Count; i++)
                    {
                        try
                        {
                            GSItem cal = new GSItem();
                            cal.Title = calFeed.Entries[i].Title.Text;
                            cal.Id = getUlrFromFeed(calFeed.Entries[i], "alternate");
                            calendari.Add(cal.Title.ToString(),
                                            cal );
                            Debug.WriteLine(calFeed.Entries[i].Title.Text);
                        }
                        catch(Exception e)
                        {
                            Debug.WriteLine(e.StackTrace);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.StackTrace);
                if (e.InnerException!=null && e.InnerException.Message.IndexOf("403") > -1)
                {
                    Exception myex = new Exception(e.InnerException.Message+"\n"+Properties.Resources.MSG_ERROR_403, e);
                    throw myex;
                }
                else if (e.InnerException != null && e.InnerException.Message.IndexOf("Could not establish connection") > -1)
                {
                    Exception myex = new Exception(e.InnerException.Message , e);
                    throw myex;
                }
                throw e;
                
            }
            ArrayList result = new ArrayList();
            
            return calendari.Values;
        }

        static String getUlrFromFeed(AtomEntry entry, String rel)
        {
            String alternateLink = "";
            foreach (AtomLink link in entry.Links)
            {
                if (link.Rel == rel)
                {
                    alternateLink = link.HRef.Content;
                }
            }
            return alternateLink;
        }

        public ArrayList GetAllEventsByName(String itemName,String extraQuery,String textFilter)
        {
            if (calendari == null)
            {
                throw new Exception(Properties.Resources.BUTTON_LOAD_CAL+Properties.Resources.LABEL_TAB_GCAL);
            }
            String FeedUriN = ((GSItem)calendari[itemName]).Id.ToString();
            return GetAllEvents(FeedUriN, extraQuery, textFilter);
        }


        public String getFeedURI(String gcalName)
        {
            return calendari[gcalName].ToString();
        }


      ///  public ArrayList GetAllEvents(String FeedUriN)
      //  {
      //      return GetAllEvents(FeedUriN, null);
      //  }
        /// <summary>
        /// Prints the titles of all events on the specified calendar.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        public ArrayList GetAllEvents(String FeedUriN, String extraQuery,String textFilter)
        {
            //String FeedUriN = calendari[itemName].ToString();
            EventQuery myQuery = new EventQuery(FeedUriN);
           // myQuery.StartTime = new DateTime();
           // myQuery.EndTime = new DateTime().AddYears(2);
            //myQuery.FutureEvents = true;
            myQuery.SingleEvents = false;
            myQuery.SortOrder = CalendarSortOrder.ascending;
            if (textFilter != null && textFilter.Trim().Length > 0)
            {
                myQuery.Query = textFilter;
            }
            myQuery.ExtraParameters = extraQuery;//"orderby=starttime";
            /*
            if (maxResult != 25)
            {
                myQuery.ExtraParameters += "&max-results="+maxResult;
            }
             */ 
            EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;
            ArrayList items = new ArrayList(1);
            events = new Hashtable();
            if (myResultsFeed != null && myResultsFeed.Entries.Count>0)
            {
                Debug.WriteLine("All events on your calendar:");
               
                items = new ArrayList(myResultsFeed.Entries.Count);
                for (int i = 0; i < myResultsFeed.Entries.Count; i++)
                {   
                    EventEntry eventEntry=(EventEntry)myResultsFeed.Entries[i];
                    
                    //String date = (eventEntry.Times.Count > 0 ? eventEntry.Times[0].StartTime.ToString() : eventEntry.Recurrence.Value);
                    //Debug.WriteLine(eventEntry.Title.Text +"-"+ date);

                    String eventDate = (eventEntry.Times.Count > 0 ?String.Format(" {0:M}", eventEntry.Times[0].StartTime): eventEntry.Recurrence.Value);
                    GSItem item = new GSItem();
                    item.Title = eventEntry.Title.Text + "  " + eventDate;
                    item.Id=eventEntry.Title.Text + "--(" + eventEntry.EventId + ")";
                    items.Add(item);
                    events.Add(eventEntry.Title.Text + "--(" + eventEntry.EventId + ")", eventEntry);
                }               
            }
            return items;
        }

        public EventEntry getEventEntry(String title)
        {
            return (EventEntry)events[title];
        }

        /// <summary>
        /// Prints the titles of all events matching a full-text query.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        /// <param name="queryString">The text for which to query.</param>
         void FullTextQuery(CalendarService service, String queryString)
        {
            EventQuery myQuery = new EventQuery(FeedUri);
            myQuery.Query = queryString;
            myQuery.FutureEvents = true;
            EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;

            Debug.WriteLine("Events matching \"{0}\":", queryString);
            
            for (int i = 0; i < myResultsFeed.Entries.Count; i++)
            {
                Debug.WriteLine(myResultsFeed.Entries[i].Title.Text);
            }
            
        }

        /// <summary>
        /// Prints the titles of all events in a specified date/time range.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        /// <param name="startTime">Start time (inclusive) of events to print.</param>
        /// <param name="endTime">End time (exclusive) of events to print.</param>
         void DateRangeQuery(CalendarService service, DateTime startTime, DateTime endTime)
        {
            EventQuery myQuery = new EventQuery(FeedUri);
            myQuery.StartTime = startTime;
            myQuery.EndTime = endTime;

            EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;

            Debug.WriteLine("Matching events from "+startTime.ToShortDateString()+" to "+endTime.ToShortDateString()+":");
            
            for (int i = 0; i < myResultsFeed.Entries.Count; i++)
            {
                Debug.WriteLine(myResultsFeed.Entries[i].Title.Text);
            }
            
        }

        /// <summary>
        /// Helper method to create either single-instance or recurring events.
        /// For simplicity, some values that might normally be passed as parameters
        /// (such as author name, email, etc.) are hard-coded.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        /// <param name="entryTitle">Title of the event to create.</param>
        /// <param name="recurData">Recurrence value for the event, or null for
        ///                         single-instance events.</param>
        /// <returns>The newly-created EventEntry on the calendar.</returns>
         EventEntry CreateEvent(CalendarService service, String entryTitle,
                                     String recurData)
        {
            EventEntry entry = new EventEntry();

            // Set the title and content of the entry.
            entry.Title.Text = entryTitle;
            entry.Content.Content = "Meet for a quick lesson.";

            // Set a location for the event.
            Where eventLocation = new Where();
            eventLocation.ValueString = "South Tennis Courts";
            entry.Locations.Add(eventLocation);

            // If a recurrence was requested, add it.  Otherwise, set the
            // time (the current date and time) and duration (30 minutes)
            // of the event.
            if (recurData == null) {
                When eventTime = new When();
                eventTime.StartTime = DateTime.Now;
                eventTime.EndTime = eventTime.StartTime.AddMinutes(30);
                entry.Times.Add(eventTime);
            } else {
                Recurrence recurrence = new Recurrence();
                recurrence.Value = recurData;
                entry.Recurrence = recurrence;
            }

            // Send the request and receive the response:
            Uri postUri = new Uri(FeedUri);
            AtomEntry insertedEntry = service.Insert(postUri, entry);

            return (EventEntry)insertedEntry;
        }

        /// <summary>
        /// Creates a single-instance event on a calendar.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        /// <param name="entryTitle">Title of the event to create.</param>
        /// <returns>The newly-created EventEntry on the calendar.</returns>
         EventEntry CreateSingleEvent(CalendarService service, String entryTitle)
        {
            return CreateEvent(service, entryTitle, null);
        }

        /// <summary>
        /// Creates a recurring event on a calendar. In this example, the event
        /// occurs every Tuesday from May 1, 2007 through September 4, 2007. Note
        /// that we are using iCal (RFC 2445) syntax; see http://www.ietf.org/rfc/rfc2445.txt
        /// for more information.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        /// <param name="entryTitle">Title of the event to create.</param>
        /// <returns>The newly-created EventEntry on the calendar.</returns>
         EventEntry CreateRecurringEvent(CalendarService service, String entryTitle)
        {
            String recurData =
              "DTSTART;VALUE=DATE:20070501\r\n" +
              "DTEND;VALUE=DATE:20070502\r\n" +
              "RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20070904\r\n";

            return CreateEvent(service, entryTitle, recurData);
        }

        /// <summary>
        /// Updates the title of an existing calendar event.
        /// </summary>
        /// <param name="entry">The event to update.</param>
        /// <param name="newTitle">The new title for this event.</param>
        /// <returns>The updated EventEntry object.</returns>
         EventEntry UpdateTitle(EventEntry entry, String newTitle)
        {
            entry.Title.Text = newTitle;
            return (EventEntry)entry.Update();
        }

        /// <summary>
        /// Adds a reminder to a calendar event.
        /// </summary>
        /// <param name="entry">The event to update.</param>
        /// <param name="numMinutes">Reminder time, in minutes.</param>
        /// <returns>The updated EventEntry object.</returns>
         EventEntry AddReminder(EventEntry entry, int numMinutes)
        {
            Reminder reminder = new Reminder();
            reminder.Minutes = numMinutes;
            entry.Reminder = reminder;

            return (EventEntry)entry.Update();
        }

        /// <summary>
        /// Adds an extended property to a calendar event.
        /// </summary>
        /// <param name="entry">The event to update.</param>
        /// <returns>The updated EventEntry object.</returns>
         EventEntry AddExtendedProperty(EventEntry entry)
        {
            ExtendedProperty property = new ExtendedProperty();
            property.Name = "http://www.example.com/schemas/2005#mycal.id";
            property.Value = "1234";

            entry.ExtensionElements.Add(property);
            
            return (EventEntry)entry.Update();
        }

        /// <summary>
        /// Retrieves and prints the access control lists of all
        /// of the authenticated user's calendars.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
         void RetrieveAcls(CalendarService service)
        {
            FeedQuery query = new FeedQuery("http://www.google.com/calendar/feeds/default");
            AtomFeed calFeed = service.Query(query);

            
            Debug.WriteLine("Sharing permissions for your calendars:");

            // Retrieve the meta-feed of all calendars.
            foreach (AtomEntry calendarEntry in calFeed.Entries)
            {
                Debug.WriteLine("Calendar: {0}", calendarEntry.Title.Text);
                AtomLink link = calendarEntry.Links.FindService(
                    AclNameTable.LINK_REL_ACCESS_CONTROL_LIST, null);

                // For each calendar, retrieve its ACL feed.
                if (link != null)
                {
                    AclFeed feed = service.Query(new AclQuery(link.HRef.ToString()));
                    foreach (AclEntry aclEntry in feed.Entries)
                    {
                        Debug.WriteLine("\tScope: Type="+aclEntry.Scope.Type+" ("+ aclEntry.Scope.Value+")");
                        Debug.WriteLine("\tRole: "+ aclEntry.Role.Value);
                    }
                }
            }
        }

        /// <summary>
        /// Shares a calendar with the specified user.  Note that this method
        /// will not run by default.
        /// </summary>
        /// <param name="service">The authenticated CalendarService object.</param>
        /// <param name="aclFeedUri">the ACL feed URI of the calendar being shared.</param>
        /// <param name="userEmail">The email address of the user with whom to share.</param>
        /// <param name="role">The role of the user with whom to share.</param>
        /// <returns>The AclEntry returned by the server.</returns>
         AclEntry AddAccessControl(CalendarService service, string aclFeedUri,
            string userEmail, AclRole role)
        {
            AclEntry entry = new AclEntry();

            entry.Scope = new AclScope();
            entry.Scope.Type = AclScope.SCOPE_USER;
            entry.Scope.Value = userEmail;

            entry.Role = role;

            Uri aclUri =
                new Uri("http://www.google.com/calendar/feeds/gdata.ops.test@gmail.com/acl/full");

            AclEntry insertedEntry = service.Insert(aclUri, entry) as AclEntry;
            Debug.WriteLine("Added user {0}", insertedEntry.Scope.Value);

            return insertedEntry;
        }

        /// <summary>
        /// Updates a user to have new access permissions over a calendar.
        /// Note that this method will not run by default.
        /// </summary>
        /// <param name="entry">An existing AclEntry representing sharing permissions.</param>
        /// <param name="newRole">The new role (access permissions) for the user.</param>
        /// <returns>The updated AclEntry.</returns>
         AclEntry UpdateEntry(AclEntry entry, AclRole newRole)
        {
            entry.Role = newRole;
            AclEntry updatedEntry = entry.Update() as AclEntry;

            Debug.WriteLine("Updated "+updatedEntry.Scope.Value+" to have role "+entry.Role.Value);
            return updatedEntry;
        }

        /// <summary>
        /// Deletes a user from a calendar's access control list, preventing
        /// that user from accessing the calendar.  Note that this method will
        /// not run by default.
        /// </summary>
        /// <param name="entry">An existing AclEntry representing sharing permissions.</param>
         void DeleteEntry(AclEntry entry)
        {
            entry.Delete();
        }


        public GCalendar(String UserName, String UserPassword)
        {
            this.UserName = UserName;
            this.UserPassword = UserPassword;
            service = new CalendarService(GManager.appService);
            service.setUserCredentials(UserName, UserPassword);
            
        }

        /// <summary>
        /// Runs the methods above to demonstrate usage of the .NET
        /// client library.  The methods that add, update, or remove
        /// users on access control lists will not run by default.
        /// </summary>
        public  void RunSample()
        {

            CalendarService service = new CalendarService(GManager.appService);
            service.setUserCredentials(UserName, UserPassword);
            
            // Demonstrate retrieving a list of the user's calendars.
            return;// RetriveUserCalendars();
            
            //FeedUri = "http://www.google.com/calendar/feeds/default/allcalendars/full";
            //return PrintAllEvents(service);
            /*
            // Demonstrate various feed queries.
            
            FullTextQuery(service, "Tennis");
            DateRangeQuery(service, new DateTime(2007, 1, 5), new DateTime(2007, 1, 7));

            // Demonstrate creating a single-occurrence event.
            EventEntry singleEvent = CreateSingleEvent(service, "Tennis with Mike");
            Debug.WriteLine("Successfully created event {0}", singleEvent.Title.Text);

            // Demonstrate creating a recurring event.
            AtomEntry recurringEvent = CreateRecurringEvent(service, "Tennis with Dan");
            Debug.WriteLine("Successfully created recurring event {0}", recurringEvent.Title.Text);

            // Demonstrate updating the event's text.
            singleEvent = UpdateTitle(singleEvent, "Important meeting");
            Debug.WriteLine("Event's new title is {0}", singleEvent.Title.Text);

            // Demonstrate adding a reminder.  Note that this will only work on a primary
            // calendar.
            singleEvent = AddReminder(singleEvent, 15);
            Debug.WriteLine("Set a {0}-minute reminder for the event.", singleEvent.Reminder.Minutes);

            // Demonstrate adding an extended property.
            AddExtendedProperty(singleEvent);

            // Demonstrate deleting the item.
            singleEvent.Delete();

            // Demonstrate retrieving access control lists for all calendars.
            RetrieveAcls(service);
             * */
        }
        /*
        static void Main(string[] args)
        {
            if (args.Length != 3)
            {
                Debug.WriteLine("Usage: gcal_demo <username> <password> <feedUri>");
            }
            else
            {
                userName = args[0];
                userPassword = args[1];
                feedUri = args[2];

                RunSample();
            }
        }
         */
    }
    
}
